View Javadoc
1   package org.apache.maven.surefire.junitcore;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.surefire.booter.Command;
23  import org.apache.maven.surefire.booter.CommandListener;
24  import org.apache.maven.surefire.booter.CommandReader;
25  import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
26  import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener;
27  import org.apache.maven.surefire.common.junit4.Notifier;
28  import org.apache.maven.surefire.common.junit48.FilterFactory;
29  import org.apache.maven.surefire.common.junit48.JUnit48Reflector;
30  import org.apache.maven.surefire.common.junit48.JUnit48TestChecker;
31  import org.apache.maven.surefire.providerapi.AbstractProvider;
32  import org.apache.maven.surefire.providerapi.ProviderParameters;
33  import org.apache.maven.surefire.report.ConsoleLogger;
34  import org.apache.maven.surefire.report.ReporterFactory;
35  import org.apache.maven.surefire.suite.RunResult;
36  import org.apache.maven.surefire.testset.TestListResolver;
37  import org.apache.maven.surefire.testset.TestSetFailedException;
38  import org.apache.maven.surefire.util.RunOrderCalculator;
39  import org.apache.maven.surefire.util.ScanResult;
40  import org.apache.maven.surefire.util.ScannerFilter;
41  import org.apache.maven.surefire.util.TestsToRun;
42  import org.junit.runner.manipulation.Filter;
43  import org.junit.runner.notification.Failure;
44  import org.junit.runner.notification.RunListener;
45  
46  import java.util.Collection;
47  import java.util.List;
48  import java.util.Map;
49  import java.util.Set;
50  import java.util.concurrent.ConcurrentHashMap;
51  
52  import static java.util.Collections.unmodifiableCollection;
53  import static org.apache.maven.surefire.booter.CommandReader.getReader;
54  import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTests;
55  import static org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory.createCustomListeners;
56  import static org.apache.maven.surefire.common.junit4.Notifier.pureNotifier;
57  import static org.apache.maven.surefire.junitcore.ConcurrentRunListener.createInstance;
58  import static org.apache.maven.surefire.report.ConsoleOutputCapture.startCapture;
59  import static org.apache.maven.surefire.testset.TestListResolver.optionallyWildcardFilter;
60  import static org.apache.maven.surefire.util.TestsToRun.fromClass;
61  
62  /**
63   * @author Kristian Rosenvold
64   */
65  @SuppressWarnings( { "UnusedDeclaration" } )
66  public class JUnitCoreProvider
67      extends AbstractProvider
68  {
69      private final ClassLoader testClassLoader;
70  
71      private final JUnitCoreParameters jUnitCoreParameters;
72  
73      private final ScannerFilter scannerFilter;
74  
75      private final Collection<RunListener> customRunListeners;
76  
77      private final ProviderParameters providerParameters;
78  
79      private final ScanResult scanResult;
80  
81      private final int rerunFailingTestsCount;
82  
83      private final JUnit48Reflector jUnit48Reflector;
84  
85      private final RunOrderCalculator runOrderCalculator;
86  
87      private final TestListResolver testResolver;
88  
89      private final CommandReader commandsReader;
90  
91      private TestsToRun testsToRun;
92  
93      public JUnitCoreProvider( ProviderParameters bootParams )
94      {
95          // don't start a thread in CommandReader while we are in in-plugin process
96          commandsReader = bootParams.isInsideFork() ? getReader().setShutdown( bootParams.getShutdown() ) : null;
97          providerParameters = bootParams;
98          testClassLoader = bootParams.getTestClassLoader();
99          scanResult = bootParams.getScanResult();
100         runOrderCalculator = bootParams.getRunOrderCalculator();
101         jUnitCoreParameters = new JUnitCoreParameters( bootParams.getProviderProperties() );
102         scannerFilter = new JUnit48TestChecker( testClassLoader );
103         testResolver = bootParams.getTestRequest().getTestListResolver();
104         rerunFailingTestsCount = bootParams.getTestRequest().getRerunFailingTestsCount();
105         String listeners = bootParams.getProviderProperties().get( "listener" );
106         customRunListeners = unmodifiableCollection( createCustomListeners( listeners ) );
107         jUnit48Reflector = new JUnit48Reflector( testClassLoader );
108     }
109 
110     public Iterable<Class<?>> getSuites()
111     {
112         testsToRun = scanClassPath();
113         return testsToRun;
114     }
115 
116     private boolean isSingleThreaded()
117     {
118         return jUnitCoreParameters.isNoThreading();
119     }
120 
121     public RunResult invoke( Object forkTestSet )
122         throws TestSetFailedException
123     {
124         final ReporterFactory reporterFactory = providerParameters.getReporterFactory();
125 
126         final RunResult runResult;
127 
128         final ConsoleLogger consoleLogger = providerParameters.getConsoleLogger();
129 
130         Filter filter = jUnit48Reflector.isJUnit48Available() ? createJUnit48Filter() : null;
131 
132         Notifier notifier =
133             new Notifier( createRunListener( reporterFactory, consoleLogger ), getSkipAfterFailureCount() );
134         // startCapture() called in createRunListener() in prior to setTestsToRun()
135 
136         if ( testsToRun == null )
137         {
138             setTestsToRun( forkTestSet );
139         }
140 
141         // Add test failure listener
142         JUnitTestFailureListener testFailureListener = new JUnitTestFailureListener();
143         notifier.addListener( testFailureListener );
144 
145         if ( isFailFast() && commandsReader != null )
146         {
147             registerPleaseStopJUnitListener( notifier );
148         }
149 
150         try
151         {
152             JUnitCoreWrapper core = new JUnitCoreWrapper( notifier, jUnitCoreParameters, consoleLogger );
153 
154             if ( commandsReader != null )
155             {
156                 registerShutdownListener( testsToRun );
157                 commandsReader.awaitStarted();
158             }
159 
160             notifier.asFailFast( isFailFast() );
161             core.execute( testsToRun, customRunListeners, filter );
162             notifier.asFailFast( false );
163 
164             // Rerun failing tests if rerunFailingTestsCount is larger than 0
165             if ( isRerunFailingTests() )
166             {
167                 Notifier rerunNotifier = pureNotifier();
168                 notifier.copyListenersTo( rerunNotifier );
169                 JUnitCoreWrapper rerunCore = new JUnitCoreWrapper( rerunNotifier, jUnitCoreParameters, consoleLogger );
170                 for ( int i = 0; i < rerunFailingTestsCount && !testFailureListener.getAllFailures().isEmpty(); i++ )
171                 {
172                     List<Failure> failures = testFailureListener.getAllFailures();
173                     Map<Class<?>, Set<String>> failingTests = generateFailingTests( failures, testClassLoader );
174                     testFailureListener.reset();
175                     FilterFactory filterFactory = new FilterFactory( testClassLoader );
176                     Filter failingMethodsFilter = filterFactory.createFailingMethodFilter( failingTests );
177                     rerunCore.execute( testsToRun, failingMethodsFilter );
178                 }
179             }
180         }
181         finally
182         {
183             runResult = reporterFactory.close();
184             notifier.removeListeners();
185         }
186         return runResult;
187     }
188 
189     private void setTestsToRun( Object forkTestSet )
190         throws TestSetFailedException
191     {
192         if ( forkTestSet instanceof TestsToRun )
193         {
194             testsToRun = (TestsToRun) forkTestSet;
195         }
196         else if ( forkTestSet instanceof Class )
197         {
198             Class<?> theClass = (Class<?>) forkTestSet;
199             testsToRun = fromClass( theClass );
200         }
201         else
202         {
203             testsToRun = scanClassPath();
204         }
205     }
206 
207     private boolean isRerunFailingTests()
208     {
209         return rerunFailingTestsCount > 0;
210     }
211 
212     private boolean isFailFast()
213     {
214         return providerParameters.getSkipAfterFailureCount() > 0;
215     }
216 
217     private int getSkipAfterFailureCount()
218     {
219         return isFailFast() ? providerParameters.getSkipAfterFailureCount() : 0;
220     }
221 
222     private void registerShutdownListener( final TestsToRun testsToRun )
223     {
224         commandsReader.addShutdownListener( new CommandListener()
225         {
226             public void update( Command command )
227             {
228                 testsToRun.markTestSetFinished();
229             }
230         } );
231     }
232 
233     private void registerPleaseStopJUnitListener( final Notifier stoppable )
234     {
235         commandsReader.addSkipNextTestsListener( new CommandListener()
236         {
237             public void update( Command command )
238             {
239                 stoppable.pleaseStop();
240             }
241         } );
242     }
243 
244     private JUnit4RunListener createRunListener( ReporterFactory reporterFactory, ConsoleLogger consoleLogger )
245         throws TestSetFailedException
246     {
247         if ( isSingleThreaded() )
248         {
249             NonConcurrentRunListener rm = new NonConcurrentRunListener( reporterFactory.createReporter() );
250             startCapture( rm );
251             return rm;
252         }
253         else
254         {
255             final Map<String, TestSet> testSetMap = new ConcurrentHashMap<String, TestSet>();
256 
257             ConcurrentRunListener listener = createInstance( testSetMap, reporterFactory, isParallelTypes(),
258                                                              isParallelMethodsAndTypes(), consoleLogger );
259             startCapture( listener );
260 
261             return new JUnitCoreRunListener( listener, testSetMap );
262         }
263     }
264 
265     private boolean isParallelMethodsAndTypes()
266     {
267         return jUnitCoreParameters.isParallelMethods() && isParallelTypes();
268     }
269 
270     private boolean isParallelTypes()
271     {
272         return jUnitCoreParameters.isParallelClasses() || jUnitCoreParameters.isParallelSuites();
273     }
274 
275     private Filter createJUnit48Filter()
276     {
277         final FilterFactory factory = new FilterFactory( testClassLoader );
278         Map<String, String> props = providerParameters.getProviderProperties();
279         Filter groupFilter = factory.canCreateGroupFilter( props ) ? factory.createGroupFilter( props ) : null;
280         TestListResolver methodFilter = optionallyWildcardFilter( testResolver );
281         boolean onlyGroups = methodFilter.isEmpty() || methodFilter.isWildcard();
282         if ( onlyGroups )
283         {
284             return groupFilter;
285         }
286         else
287         {
288             Filter jUnitMethodFilter = factory.createMethodFilter( methodFilter );
289             return groupFilter == null ? jUnitMethodFilter : factory.and( groupFilter, jUnitMethodFilter );
290         }
291     }
292 
293     private TestsToRun scanClassPath()
294     {
295         TestsToRun scanned = scanResult.applyFilter( scannerFilter, testClassLoader );
296         return runOrderCalculator.orderTestClasses( scanned );
297     }
298 }